package com.jweb.framework.core.config;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;


public class TopBeanParser extends AbstractSingleBeanDefinitionParser {
	
	private Class clazz ;
	
	public TopBeanParser(Class cls){
		this.clazz = cls ;
	}
	
	protected Class getBeanClass(Element ele){
		return TopLevelBeanFactoryBean.class ;
	}
	
	public static class TopLevelBeanFactoryBean<T> implements FactoryBean<T> {
		
		private T obj ;
		
		private Class clazz ;
		
		public TopLevelBeanFactoryBean(String nam , Class clazz , T obj) {
			if(!clazz.isInstance(obj)){
				throw new IllegalStateException("element <" + nam + ">'s class not match required type: " + clazz.getName());
			}
			this.obj = obj ;
			this.clazz = clazz ;
		}
		
		public  T getObject() throws Exception {
			return this.obj ;
		}
		
		public Class<?> getObjectType(){
			return this.clazz ;
		}
		
		public boolean isSingleton(){
			return true ;
		}
		
	}
	
	protected void doParse(Element ele , ParserContext parserContext , BeanDefinitionBuilder beanDefinitionBuilder){
		
		beanDefinitionBuilder.addConstructorArgValue(ele.getNodeName());
		beanDefinitionBuilder.addConstructorArgValue(this.clazz);
		
		String ref = ele.getAttribute("ref");
		if(StringUtils.hasText(ref)){
			beanDefinitionBuilder.addConstructorArgReference(ref);
		}
		else {
			BeanDefinitionHolder bHolder = parserContext.getDelegate().parseBeanDefinitionElement(ele , beanDefinitionBuilder.getRawBeanDefinition());
			if(bHolder != null){
				bHolder = parserContext.getDelegate().decorateBeanDefinitionIfRequired(ele , bHolder , beanDefinitionBuilder.getRawBeanDefinition());
			}
			else {
				parserContext.getReaderContext().error("cannot build bean" , ele);
			}
			
			beanDefinitionBuilder.addConstructorArgValue(bHolder);
		}
	}
	
}
